/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package proyecto;

/**
 *
 * @author Luis Romero
 */
import java.util.logging.Level;
import java.util.logging.Logger;
import static proyecto.Constantes.*;

public class IF extends Thread {

    int PC;
    SharedMem MInt;
    CacheInstrucciones CI;
    ID SIG;
    boolean repite;
    final Object lock;
    Nucleo N;
    Reloj reloj;

    IF(CacheInstrucciones cache) {
        MInt = new SharedMem();
        PC = 0;
        CI = cache;
        this.setName("IF");
        repite = true;
        lock = new Object();
    }

    public void setEtapas(ID id) {
        SIG = id;
    }

    public void setPC(int NPC) {
        PC = NPC;
    }
    
    public void setReloj(Reloj reloj){
        this.reloj = reloj;
    }

    public void parar() {
        synchronized (lock) {
            try {
               // System.out.println("Parar IF");
                lock.wait();
            } catch (InterruptedException ex) {
                Logger.getLogger(ID.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public void seguir() {
        synchronized (lock) {
           // System.out.println("Seguir IF");
            lock.notify();
        }
    }

    public void setNucleo(Nucleo n){
        N=n;
    }

    @Override
    public void run() {
        System.out.println("Inicio de IF");
        //SIG.start();
        N.seguir();
        this.parar();
        while (repite) { 
            //this.parar();
            int[] instruccion = new int[4];
            //Pedir la instruccion PC
            instruccion = CI.getInstruccion(PC, PC/4);
            System.out.println("IF: "+instruccion[0]+instruccion[1]+instruccion[2]+instruccion[3]);
            //Almacenar la instruccion en SharedMem al igual que los datos necesarios
            switch (instruccion[0]) {
                case DADDI:
                    SIG.MInt.setReg(INST, instruccion[0]);
                    SIG.MInt.setReg(REGD, instruccion[2]);
                    SIG.MInt.setReg(REGF1, instruccion[1]);
                    SIG.MInt.setReg(REGF2, instruccion[3]);
                    break;
                case DADD:
                    SIG.MInt.setReg(INST, instruccion[0]);
                    SIG.MInt.setReg(REGD, instruccion[3]);
                    SIG.MInt.setReg(REGF1, instruccion[1]);
                    SIG.MInt.setReg(REGF2, instruccion[2]);
                    break;
                case DSUB:
                    SIG.MInt.setReg(INST, instruccion[0]);
                    SIG.MInt.setReg(REGD, instruccion[3]);
                    SIG.MInt.setReg(REGF1, instruccion[1]);
                    SIG.MInt.setReg(REGF2, instruccion[2]);
                    break;
                case DDIV:
                    SIG.MInt.setReg(INST, instruccion[0]);
                    SIG.MInt.setReg(REGD, instruccion[3]);
                    SIG.MInt.setReg(REGF1, instruccion[1]);
                    SIG.MInt.setReg(REGF2, instruccion[2]);
                    break;
                case DMUL:
                    SIG.MInt.setReg(INST, instruccion[0]);
                    SIG.MInt.setReg(REGD, instruccion[3]);
                    SIG.MInt.setReg(REGF1, instruccion[1]);
                    SIG.MInt.setReg(REGF2, instruccion[2]);
                    break;
                case LW:
                    SIG.MInt.setReg(INST, instruccion[0]);
                    SIG.MInt.setReg(REGD, instruccion[2]);
                    SIG.MInt.setReg(REGF1, instruccion[1]);
                    SIG.MInt.setReg(REGF2, instruccion[3]);
                    break;
                case SW:
                    SIG.MInt.setReg(INST, instruccion[0]);
                    SIG.MInt.setReg(REGD, instruccion[2]);
                    SIG.MInt.setReg(REGF1, instruccion[1]);
                    SIG.MInt.setReg(REGF2, instruccion[3]);
                    break;
                case BEQZ:
                    SIG.MInt.setReg(INST, instruccion[0]);
                    SIG.MInt.setReg(REGD, instruccion[2]);
                    SIG.MInt.setReg(REGF1, instruccion[1]);
                    SIG.MInt.setReg(REGF2, instruccion[3]);
                    break;
                case BNEZ:
                    SIG.MInt.setReg(INST, instruccion[0]);
                    SIG.MInt.setReg(REGD, instruccion[2]);
                    SIG.MInt.setReg(REGF1, instruccion[1]);
                    SIG.MInt.setReg(REGF2, instruccion[3]);
                    break;
                case JAL:
                    SIG.MInt.setReg(INST, instruccion[0]);
                    SIG.MInt.setReg(REGD, instruccion[2]);
                    SIG.MInt.setReg(REGF1, instruccion[1]);
                    SIG.MInt.setReg(REGF2, instruccion[3]);
                    break;
                case JR:
                    SIG.MInt.setReg(INST, instruccion[0]);
                    SIG.MInt.setReg(REGD, instruccion[2]);
                    SIG.MInt.setReg(REGF1, instruccion[1]);
                    SIG.MInt.setReg(REGF2, instruccion[3]);
                    break;
                case LL:
                    SIG.MInt.setReg(INST, instruccion[0]);
                    SIG.MInt.setReg(REGD, instruccion[2]);
                    SIG.MInt.setReg(REGF1, instruccion[1]);
                    SIG.MInt.setReg(REGF2, instruccion[3]);
                    break;
                case SC:
                    SIG.MInt.setReg(INST, instruccion[0]);
                    SIG.MInt.setReg(REGD, instruccion[2]);
                    SIG.MInt.setReg(REGF1, instruccion[1]);
                    SIG.MInt.setReg(REGF2, instruccion[3]);
                    break;
                case FIN:
                    SIG.MInt.setReg(INST, instruccion[0]);
                    SIG.MInt.setReg(REGD, instruccion[2]);
                    SIG.MInt.setReg(REGF1, instruccion[1]);
                    SIG.MInt.setReg(REGF2, instruccion[3]);
                    repite = false;
                    break;

            }
            
            reloj.cuentaHilo(0);
            reloj.seguir();
            //Determinar si se acabo el cuantum para iniciar la interrupcion
            if(reloj.getTicks()>N.Quantum){
                //Va a realizar la interrupcion del hilo
                SIG.MInt.setReg(INST, INTERRUPT);
                SIG.MInt.setReg(NPC, PC);
                repite = false;
            }


            //Poner a correr al hilo ID
            PC = PC + 4;
            SIG.seguir();
            this.parar();
            if(!repite){
                SIG.seguir();
            }
            
        }
        System.out.println("Murio IF");
    }
}
